#region Install-LWLabCAServers
function Install-LWLabCAServers
{
	[Cmdletbinding()]
	param (
		[Parameter(Mandatory = $true)][string]$ComputerName,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$DomainName,
		[Parameter(Mandatory = $true)][string]$UserName,
		[Parameter(Mandatory = $true)][string]$Password,
		[Parameter(Mandatory = $false)][string]$ForestAdminUserName,
		[Parameter(Mandatory = $false)][string]$ForestAdminPassword,
		[Parameter(Mandatory = $false)][string]$ParentCA,
		[Parameter(Mandatory = $false)][string]$ParentCALogicalName,
		[Parameter(Mandatory = $true)][string]$CACommonName,
		[Parameter(Mandatory = $true)][string]$CAType,
		[Parameter(Mandatory = $true)][string]$KeyLength,
		[Parameter(Mandatory = $true)][string]$CryptoProviderName,
		[Parameter(Mandatory = $true)][string]$HashAlgorithmName,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$DatabaseDirectory,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$LogDirectory,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$CpsUrl,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$CpsText,
		[Parameter(Mandatory = $true)][boolean]$UseLDAPAIA,
		[Parameter(Mandatory = $true)][boolean]$UseHttpAia,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$AiaHttpUrl01,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$AiaHttpUrl02,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$AiaHttpUrl01UploadLocation,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$AiaHttpUrl02UploadLocation,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$OCSPHttpUrl01,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$OCSPHttpUrl02,
		[Parameter(Mandatory = $true)][boolean]$UseLDAPCRL,
		[Parameter(Mandatory = $true)][boolean]$UseHttpCRL,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$CdpHttpUrl01,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$CdpHttpUrl02,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$CdpHttpUrl01UploadLocation,
		[Parameter(Mandatory = $true)][AllowEmptyString()][string]$CdpHttpUrl02UploadLocation,
		[Parameter(Mandatory = $true)][boolean]$InstallOCSP,
		[Parameter(Mandatory = $false)][string]$ValidityPeriod,
		[Parameter(Mandatory = $false)][int]$ValidityPeriodUnits,
		[Parameter(Mandatory = $true)][string]$CRLPeriod,
		[Parameter(Mandatory = $true)][int]$CRLPeriodUnits,
		[Parameter(Mandatory = $true)][string]$CRLOverlapPeriod,
		[Parameter(Mandatory = $true)][int]$CRLOverlapUnits,
		[Parameter(Mandatory = $true)][string]$CRLDeltaPeriod,
		[Parameter(Mandatory = $true)][int]$CRLDeltaPeriodUnits,
		[Parameter(Mandatory = $true)][string]$CertsValidityPeriod,
		[Parameter(Mandatory = $true)][int]$CertsValidityPeriodUnits,
		[Parameter(Mandatory = $true)][boolean]$InstallWebEnrollment,
		[Parameter(Mandatory = $true)][boolean]$InstallWebRole,
		[Parameter(Mandatory = $true)][boolean]$DoNotLoadDefaultTemplates,
		[Parameter(Mandatory = $false)][int]$PreDelaySeconds
	)
	
    Write-LogFunctionEntry
	
	#region - Create parameter table
	$param = @{ }
	$param.Add('ComputerName', $ComputerName)
	$param.add('DomainName', $DomainName)
	
	$param.Add('UserName', $UserName)
	$param.Add('Password', $Password)
	$param.Add('ForestAdminUserName', $ForestAdminUserName)
	$param.Add('ForestAdminPassword', $ForestAdminPassword)
	
	$param.Add('CACommonName', $CACommonName)
	
	$param.Add('CAType', $CAType)

	$param.Add('CryptoProviderName', $CryptoProviderName)
	$param.Add('HashAlgorithmName', $HashAlgorithmName)

	$param.Add('KeyLength', $KeyLength)
	
	$param.Add('CertEnrollFolderPath', $CertEnrollFolderPath)
	$param.Add('DatabaseDirectory', $DatabaseDirectory)
	$param.Add('LogDirectory', $LogDirectory)
	
	$param.Add('CpsUrl', $CpsUrl)
	$param.Add('CpsText', """$($CpsText)""")
	
	$param.Add('UseLDAPAIA', $UseLDAPAIA)
	$param.Add('UseHttpAIA', $UseHttpAIA)
	$param.Add('AiaHttpUrl01', $AiaHttpUrl01)
	$param.Add('AiaHttpUrl02', $AiaHttpUrl02)
	$param.Add('AiaHttpUrl01UploadLocation', $AiaHttpUrl01UploadLocation)
	$param.Add('AiaHttpUrl02UploadLocation', $AiaHttpUrl02UploadLocation)
	
	$param.Add('OCSPHttpUrl01', $OCSPHttpUrl01)
	$param.Add('OCSPHttpUrl02', $OCSPHttpUrl02)
	
	$param.Add('UseLDAPCRL', $UseLDAPCRL)
	$param.Add('UseHttpCRL', $UseHttpCRL)
	$param.Add('CdpHttpUrl01', $CdpHttpUrl01)
	$param.Add('CdpHttpUrl02', $CdpHttpUrl02)
	$param.Add('CdpHttpUrl01UploadLocation', $CdpHttpUrl01UploadLocation)
	$param.Add('CdpHttpUrl02UploadLocation', $CdpHttpUrl02UploadLocation)
	
	$param.Add('InstallOCSP', $InstallOCSP)
	
	$param.Add('ValidityPeriod', $ValidityPeriod)
	$param.Add('ValidityPeriodUnits', $ValidityPeriodUnits)
	$param.Add('CRLPeriod', $CRLPeriod)
	$param.Add('CRLPeriodUnits', $CRLPeriodUnits)
	$param.Add('CRLOverlapPeriod', $CRLOverlapPeriod)
	$param.Add('CRLOverlapUnits', $CRLOverlapUnits)
	$param.Add('CRLDeltaPeriod', $CRLDeltaPeriod)
	$param.Add('CRLDeltaPeriodUnits', $CRLDeltaPeriodUnits)
	$param.Add('CertsValidityPeriod', $CertsValidityPeriod)
	$param.Add('CertsValidityPeriodUnits', $CertsValidityPeriodUnits)
	
	$param.Add('InstallWebEnrollment', $InstallWebEnrollment)
	
	$param.Add('InstallWebRole', $InstallWebRole)
	
	$param.Add('DoNotLoadDefaultTemplates', $DoNotLoadDefaultTemplates)
	
	#For Subordinate CAs only
	if ($ParentCA) { $param.add('ParentCA', $ParentCA) }
	if ($ParentCALogicalname) { $param.add('ParentCALogicalname', $ParentCALogicalName) }
	
	$param.Add('PreDelaySeconds', $PreDelaySeconds)
	#endregion - Create parameter table
	

	
	#region - Parameters debug
	Write-Debug -Message '---------------------------------------------------------------------------------------'
	Write-Debug -Message 'Parameters - Entered Install-LWLabCAServers'
	Write-Debug -Message '---------------------------------------------------------------------------------------'
	if ($param.GetEnumerator().count)
	{
		foreach ($key in ($param.GetEnumerator() | Sort-Object -Property Name)) { Write-Debug -message "  $($key.key.padright(27)) $($key.value)" }
	}
	else
	{
		Write-Debug -message '  No parameters specified'
	}
	Write-Debug -Message '---------------------------------------------------------------------------------------'
	Write-Debug -Message ''
	#endregion - Parameters debug
	
	


	#region ScriptBlock for installation
	$caScriptBlock = {
		
		param ($param)
		
        #Make semi-sure that each install of CA server is not done at the same time
        Start-Sleep -Seconds $param.PreDelaySeconds
		
		Import-Module -Name ServerManager
		
		#region - Check if CA is already installed
		if ((Get-WindowsFeature -Name 'ADCS-Cert-Authority').Installed)
		{
			Write-Output "A Certificate Authority is already installed on '$($param.ComputerName)'. Skipping installation."
			return
		}
		#endregion
		
		
		#region - Create CAPolicy file
		$caPolicyFileName = "$Env:Windir\CAPolicy.inf"
		Set-Content $caPolicyFileName -Force -Value ';CAPolicy for CA'
		Add-Content $caPolicyFileName -Value '; Please replace sample CPS OID with your own OID'
		Add-Content $caPolicyFileName -Value ''
		Add-Content $caPolicyFileName -Value '[Version]'
		Add-Content $caPolicyFileName -Value "Signature=`"`$Windows NT`$`" "
		Add-Content $caPolicyFileName -Value ''
		Add-Content $caPolicyFileName -Value '[PolicyStatementExtension]'
		Add-Content $caPolicyFileName -Value 'Policies=LegalPolicy'
		Add-Content $caPolicyFileName -Value 'Critical=0'
		Add-Content $caPolicyFileName -Value ''
		Add-Content $caPolicyFileName -Value '[LegalPolicy]'
		Add-Content $caPolicyFileName -Value 'OID=1.3.6.1.4.1.11.21.43'
		Add-Content $caPolicyFileName -Value "Notice=$($param.CpsText)"
		Add-Content $caPolicyFileName -Value "URL=$($param.CpsUrl)"
		Add-Content $caPolicyFileName -Value ''
		Add-Content $caPolicyFileName -Value '[Certsrv_Server]'
		Add-Content $caPolicyFileName -Value 'ForceUTF8=true'
		Add-Content $caPolicyFileName -Value "RenewalKeyLength=$($param.KeyLength)"
		Add-Content $caPolicyFileName -Value "RenewalValidityPeriod=$($param.ValidityPeriod)"
		Add-Content $caPolicyFileName -Value "RenewalValidityPeriodUnits=$($param.ValidityPeriodUnits)"
		Add-Content $caPolicyFileName -Value "CRLPeriod=$($param.CRLPeriod)"
		Add-Content $caPolicyFileName -Value "CRLPeriodUnits=$($param.CRLPeriodUnits)"
		Add-Content $caPolicyFileName -Value "CRLDeltaPeriod=$($param.CRLDeltaPeriod)"
		Add-Content $caPolicyFileName -Value "CRLDeltaPeriodUnits=$($param.CRLDeltaPeriodUnits)"
		Add-Content $caPolicyFileName -Value 'EnableKeyCounting=0'
		Add-Content $caPolicyFileName -Value 'AlternateSignatureAlgorithm=0'
		if ($param.DoNotLoadDefaultTemplates) { Add-Content $caPolicyFileName -Value 'LoadDefaultTemplates=0' }
		if ($param.CAType -like '*root*')
		{
			Add-Content $caPolicyFileName -Value ''
			Add-Content $caPolicyFileName -Value '[Extensions]'
			Add-Content $caPolicyFileName -Value ';Remove CA Version Index'
			Add-Content $caPolicyFileName -Value '1.3.6.1.4.1.311.21.1='
			Add-Content $caPolicyFileName -Value ';Remove CA Hash of previous CA Certificates'
			Add-Content $caPolicyFileName -Value '1.3.6.1.4.1.311.21.2='
			Add-Content $caPolicyFileName -Value ';Remove V1 Certificate Template Information'
			Add-Content $caPolicyFileName -Value '1.3.6.1.4.1.311.20.2='
			Add-Content $caPolicyFileName -Value ';Remove CA of V2 Certificate Template Information'
			Add-Content $caPolicyFileName -Value '1.3.6.1.4.1.311.21.7='
			Add-Content $caPolicyFileName -Value ';Key Usage Attribute set to critical'
			Add-Content $caPolicyFileName -Value '2.5.29.15=AwIBBg=='
			Add-Content $caPolicyFileName -Value 'Critical=2.5.29.15'
		}
		
		if ($param.DebugPref -eq 'Continue')
		{
			$file = get-content -Path "$Env:Windir\CAPolicy.inf"
			Write-Debug -Message 'CApolicy.inf contents:'
			foreach ($line in $file)
			{
				Write-Debug -Message $line
			}
		}
		#endregion - Create CAPolicy file
		
		
		#region - Install CA
		$InstallFeatures = 'Import-Module -Name ServerManager; Add-WindowsFeature -IncludeManagementTools -Name ADCS-Cert-Authority'
		# OCSP not yet supported
		#if ($param.InstallOCSP)          { $InstallFeatures += ", ADCS-Online-Cert" }
		if ($param.InstallWebEnrollment) { $InstallFeatures += ', ADCS-Web-Enrollment' }
		
		

		if ($param.ForestAdminUserName)
		{
			Write-Verbose -Message "ForestAdminUserName=$($param.ForestAdminUserName), ForestAdminPassword=$($param.ForestAdminPassword)"
			
			if ($param.DebugPref -eq 'Continue')
			{
				Write-Verbose -Message "Adding $($param.ForestAdminUserName) to local administrators group"
				Write-Verbose -Message "WinNT:://$($param.ForestAdminUserName.replace('\', '/'))"
			}
			$localGroup = ([ADSI]'WinNT://./Administrators,group')
			$localGroup.psbase.Invoke('Add', ([ADSI]"WinNT://$($param.ForestAdminUserName.replace('\', '/'))").path)
			Write-Verbose -Message "Check 2c -create credential of ""$($param.ForestAdminUserName)"" and ""$($param.ForestAdminPassword)"""
			$forestAdminCred = (New-Object System.Management.Automation.PSCredential($param.ForestAdminUserName, ($param.ForestAdminPassword | ConvertTo-SecureString -AsPlainText -Force)))
		}
		else
		{
			Write-Verbose -Message 'No ForestAdminUserName!'
		}
		
		
		

		Write-Verbose -Message 'Installing roles and features now'
		Write-Verbose -Message "Command: $InstallFeatures"
        Invoke-Expression -Command ($InstallFeatures += " -Confirm:`$false") | Out-Null
		
		Write-Verbose -Message 'Installing ADCS now'
		$installCommand = 'Install-AdcsCertificationAuthority '
		$installCommand += "-CACommonName                $($param.CACommonName) "
		$installCommand += "-CAType                      $($param.CAType) "
		$installCommand += "-KeyLength                   $($param.KeyLength) "
		$installCommand += "-CryptoProviderName          ""$($param.CryptoProviderName)"" "
		$installCommand += "-HashAlgorithmName           ""$($param.HashAlgorithmName)"" "
		$installCommand += '-OverwriteExistingKey '
		$installCommand += '-OverwriteExistingDatabase '
		$installCommand += '-Force '
		$installCommand += '-Confirm:$false '
		if ($forestAdminCred) { $installCommand += '-Credential $forestAdminCred ' }
		
		if ($param.DatabaseDirectory) { $installCommand += "-DatabaseDirectory      $($param.DatabaseDirectory) " }
		if ($param.LogDirectory)      { $installCommand += "-LogDirectory           $($param.LogDirectory) " }
		
		if ($param.CAType -like '*root*')
		{
			$installCommand += "-ValidityPeriod          $($param.ValidityPeriod) "
			$installCommand += "-ValidityPeriodUnits     $($param.ValidityPeriodUnits) "
		}
		else
		{
			$installCommand += "-ParentCA                $($param.ParentCA)`\$($param.ParentCALogicalName) "
		}
		$installCommand += ' | Out-Null'
		
		if ($param.DebugPref -eq 'Continue')
		{
			Write-Debug -Message 'Install command:'
			Write-Debug -Message $installCommand
			Set-Content -Path 'C:\debug-CAinst.txt' -value $installCommand
		}

		
        Invoke-Expression -Command $installCommand

		
		if ($param.ForestAdminUserName)
		{
			if ($param.DebugPref -eq 'Continue')
			{
				Write-Debug -Message "Removing $($param.ForestAdminUserName) to local administrators group"
			}
			$localGroup = ([ADSI]'WinNT://./Administrators,group')
			$localGroup.psbase.Invoke('Remove', ([ADSI]"WinNT://$($param.ForestAdminUserName.replace('\', '/'))").path)
		}
		
		
		if ($param.InstallWebEnrollment)
		{
			Write-Verbose -Message 'Installing Web Enrollment service now'
			Install-ADCSWebEnrollment -Confirm:$False | Out-Null
		}
		
		if ($param.InstallWebRole)
		{
			if (!(Get-WindowsFeature -Name 'web-server'))
			{
				Add-WindowsFeature -Name 'Web-Server' -IncludeManagementTools
				
				#Allow "+" characters in URL for supporting delta CRLs
				Set-WebConfiguration -Filter system.webServer/security/requestFiltering -PSPath 'IIS:\sites\Default Web Site' -Value @{allowDoubleEscaping=$true}
			}
		}
		#endregion - Install CA
		
		#region - Configure IIS virtual directories
		if ($param.UseHttpAIA)
		{
			New-WebVirtualDirectory -Site 'Default Web Site' -Name Aia -PhysicalPath 'C:\Windows\System32\CertSrv\CertEnroll' | Out-Null
			New-WebVirtualDirectory -Site 'Default Web Site' -Name Cdp -PhysicalPath 'C:\Windows\System32\CertSrv\CertEnroll' | Out-Null
		}
		#endregion - Configure IIS virtual directories
		
		#region - Configure OCSP
        <# OCSP not yet supported
        if ($InstallOCSP)
        {
            Write-Verbose -Message "Installing Online Responder"
            Install-ADCSOnlineResponder -Force | Out-Null
        }
        #>
		#endregion - Configure OCSP
		
		
		
		

		
		
		#region - Configure CA
		function Invoke-CustomExpression
		{
			param ($Command)
			
			Invoke-Expression -Command $command
            Write-Debug -Message $command
		}
		
		
		#Declare configuration NC
		if ($param.CAType -like 'Enterprise*')
		{
			$lDAPname = ''
			foreach ($part in ($param.DomainName.split('.')))
			{
				$lDAPname += ",DC=$part"
			}
			Invoke-CustomExpression -Command "certutil -setreg CA\DSConfigDN CN=Configuration$lDAPname"
		}
		
		#Apply the required CDP Extension URLs
		$command = "certutil -setreg CA\CRLPublicationURLs ""1:$($Env:WinDir)\system32\CertSrv\CertEnroll\%3%8%9.crl"
		if ($param.UseLDAPCRL) { $command += '\n11:ldap:///CN=%7%8,CN=%2,CN=CDP,CN=Public Key Services,CN=Services,%6%10' }
		if ($param.UseHttpCrl) { $command += "\n2:$($param.CdpHttpUrl01)/%3%8%9.crl" }
		$command += '"'
		Invoke-CustomExpression -Command $command
		
		#Apply the required AIA Extension URLs
		$command = "certutil -setreg CA\CACertPublicationURLs ""1:$($Env:WinDir)\system3\CertSrv\CertEnroll\%1_%3%4.crt"
		if ($param.UseLDAPAia) { $command += '\n3:ldap:///CN=%7,CN=AIA,CN=Public Key Services,CN=Services,%6%11' }
		if ($param.UseHttpAia) { $command += "\n2:$($param.AiaHttpUrl01)/%1_%3%4.crt" }
        <# OCSP not yet supported
        if ($param.InstallOCSP -and $param.OCSPHttpUrl01) { $Line += "\n34:$($param.OCSPHttpUrl01)" }
        if ($param.InstallOCSP -and $param.OCSPHttpUrl02) { $Line += "\n34:$($param.OCSPHttpUrl02)" }
        #>
		$command += '"'
		Invoke-CustomExpression -Command $command
		
		#Define default maximum certificate lifetime for issued certificates
		Invoke-CustomExpression -Command "certutil -setreg ca\ValidityPeriodUnits $($param.CertsValidityPeriodUnits)"
		Invoke-CustomExpression -Command "certutil -setreg ca\ValidityPeriod ""$($param.CertsValidityPeriod)"""
		
		#Define CRL Publication Intervals
		Invoke-CustomExpression -Command "certutil -setreg CA\CRLPeriodUnits $($param.CRLPeriodUnits)"
		Invoke-CustomExpression -Command "certutil -setreg CA\CRLPeriod ""$($param.CRLPeriod)"""
		
		#Define CRL Overlap
		Invoke-CustomExpression -Command "certutil -setreg CA\CRLOverlapUnits $($param.CRLOverlapUnits)"
		Invoke-CustomExpression -Command "certutil -setreg CA\CRLOverlapPeriod ""$($param.CRLOverlapPeriod)"""
		
		#Define Delta CRL
		Invoke-CustomExpression -Command "certutil -setreg CA\CRLDeltaUnits $($param.CRLDeltaPeriodUnits)"
		Invoke-CustomExpression -Command "certutil -setreg CA\CRLDeltaPeriod ""$($param.CRLDeltaPeriod)"""
		
		#Enable Auditing Logging
		Invoke-CustomExpression -Command 'certutil -setreg CA\Auditfilter 0x7F'
		
		#Enable UTF-8 Encoding
		Invoke-CustomExpression -Command 'certutil -setreg ca\forceteletex +0x20'
		
		if ($param.CAType -like '*root*')
		{
			#Disable Discrete Signatures in Subordinate Certificates (WinXP KB968730)
			Invoke-CustomExpression -Command 'certutil -setreg CA\csp\AlternateSignatureAlgorithm 0'
			
			#Force digital signature removal in KU for cert issuance (see also kb888180)
			Invoke-CustomExpression -Command 'certutil -setreg policy\EditFlags -EDITF_ADDOLDKEYUSAGE'
			
			#Enable SAN
			Invoke-CustomExpression -Command 'certutil -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2'
			
			#Configure policy module to automatically issue certificates when requested
			Invoke-CustomExpression -Command 'certutil -setreg ca\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\RequestDisposition 1'
		}
		#If CA is Root CA and Sub CAs are present, disable (do not publish) templates (except SubCA template)
		if ($param.DoNotLoadDefaultTemplates)
		{
			Invoke-CustomExpression -Command 'certutil -SetCATemplates +SubCA'
		}
		#endregion - Configure CA
		
        
		
		
		
		#region - Restart of CA
		if ((Get-Service -Name 'CertSvc').Status -eq 'Running')
		{
			Write-Verbose -Message 'Stopping ADCS Service'
			$totalretries = 5
			$retries = 0
			do
			{
				Stop-Service -Name 'CertSvc' -ErrorAction SilentlyContinue
				if ((Get-Service -Name 'CertSvc').Status -ne 'Stopped')
				{
					$retries++
					Start-Sleep -Seconds 1
				}
			}
			until (((Get-Service -Name 'CertSvc').Status -eq 'Stopped') -or ($retries -ge $totalretries))
            
			if ((Get-Service -Name 'CertSvc').Status -eq 'Stopped')
			{
				Write-Verbose -Message 'ADCS service is now stopped'
			}
			else
			{
				Write-Error -Message 'Could not stop ADCS Service after several retries'
				return
			}
		}

		Write-Verbose -Message 'Starting ADCS Service now'
		$totalretries = 5
		$retries = 0
		do
		{
			Start-Service -Name 'CertSvc' -ErrorAction SilentlyContinue
			if ((Get-Service -Name 'CertSvc').Status -ne 'Running')
			{
				$retries++
				Start-Sleep -Seconds 1
			}
		}
		until (((Get-Service -Name 'CertSvc').Status -eq 'Running') -or ($retries -ge $totalretries))
		
		if ((Get-Service -Name 'CertSvc').Status -eq 'Running')
		{
			Write-Verbose -Message 'ADCS service is now started'
		}
		else
		{
			Write-Error -Message 'Could not start ADCS Service after several retries'
            return
		}
		#endregion - Restart of CA
		
		
		Write-Verbose -Message 'Waiting for admin interface to be ready'
		$totalretries = 10
		$retries = 0
		do
		{
			$result = Invoke-Expression -Command "certutil -pingadmin .\$($param.CACommonName)"
			if (!($result | Where-Object { $_ -like '*interface is alive*' }))
			{
				$retries++
				Write-Verbose -Message "Admin interface not ready. Check $retries of $totalretries"
				if ($retries -lt $totalretries) { Start-Sleep -Seconds 10 }
			}
		}
		until (($result | Where-Object { $_ -like '*interface is alive*' }) -or ($retries -ge $totalretries))
		
		if ($result | Where-Object { $_ -like '*interface is alive*' })
		{
			Write-Verbose -Message 'Admin interface is now ready'
		}
		else
		{
			Write-Error -Message 'Admin interface was not ready after several retries'
            return
		}
		
		
		#region - Issue of CRL
		Start-Sleep -Seconds 2
		Invoke-Expression -Command 'certutil -crl' | Out-Null
		$totalretries = 12
		$retries = 0
		do
		{
			Start-Sleep -Seconds 5
			$retries++
		}
		until ((Get-ChildItem "$env:systemroot\system32\CertSrv\CertEnroll\*.crl") -or ($retries -ge $totalretries))
		
		#endregion - Issue of CRL
		
		if (($param.CAType -like 'Enterprise*') -and ($param.DoNotLoadDefaultTemplates)) { Invoke-Expression 'certutil -SetCATemplates +SubCA' }
    }
	
	#endregion
	
	Write-Verbose -Message "Performing installation of $($param.CAType) on '$($param.ComputerName)'"
	$cred = (New-Object System.Management.Automation.PSCredential($param.UserName, ($param.Password | ConvertTo-SecureString -AsPlainText -Force)))
	$caSession = New-LabPSSession -ComputerName $param.Computername -UseCredSsp
	$Job = Invoke-Command -Session $caSession -Scriptblock $caScriptBlock -ArgumentList $param -AsJob -JobName "Install CA on '$($param.Computername)'" -Verbose
	
    $Job
	
    Write-LogFunctionExit
}
#endregion Install-LWLabCAServers